/*
 Copyright (C) 2010 Chris Hawkins. All rights reserved.
 
 Redistribution and use in source and binary forms, with or without
 modification, are permitted provided that the following conditions are met:
 
 * Redistributions of source code must retain the above copyright notice, this
 list of conditions and the following disclaimer.
 
 * Neither the name of the author nor the names of its contributors may be used
 to endorse or promote products derived from this software without specific
 prior written permission.
 
 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
 IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE
 FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
 DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
 CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
 OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
 OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 */

#import "OpBase.h"
#import "AppDelegate_Shared.h"
#import "AsdNotification.h"
#import "ConfigManager.h"
#import "SvDictionary.h"
#import "TcError.h"

@implementation TASDSvOpBase
#pragma mark -- NSNotification and state monitoriing
- (void)            updateAwsInfo {
    AppDelegate_Shared  *appShared      = [[UIApplication sharedApplication] delegate];
    TASDConfigManager   *configMgr      = [[appShared configManager] retain];
    [cfg_Endpoint    release];
    [cfg_SigProvider release];
    cfg_Endpoint        = [[configMgr valueForProvider: [configMgr providerAwsEndpoint]]  retain];
    cfg_SigProvider     = [[configMgr valueForProvider: [configMgr providerAwsSignature]] retain];
    [[self lblAccountName]  setText: [cfg_SigProvider uniquePublicName]];
    [[self lblEndpointName] setText: [cfg_Endpoint name]];
    [configMgr release];
}
- (void)            updateAwsResponse {
    do {
        if ( asd_Request == nil ) {
            break;
        }
        NSData *data = [[asd_Request responseData] retain];
        if ( data == nil ) {
            break;
        }
        if ( tcl_AwsResponse == nil ) {
            tcl_AwsResponse = [[TASDTcAwsResponse tableCell] retain];
        }
        [tcl_AwsResponse setResponseData: data];
        if ( [asd_Request parser] != nil ) {
            [tcl_AwsResponse setParse: [asd_Request parser]];            
        }
        [self addTableViewCell: tcl_AwsResponse inSection: eASDTSvOpTableViewSection_Output];
        [data release];
    } while ( false );
}
- (void)            addError: (NSError*) error_ {
    if ( error_ != nil ) {
        if ( dCell_Error == nil ) {
            dCell_Error = [[NSMutableDictionary alloc] initWithCapacity: 4];
        }
        NSString *reason = [NSString stringWithFormat: @"code: %i", [error_ code]];
        if ( [dCell_Error objectForKey: reason] == nil ) {
            TASDTcError *cell = [TASDTcError tableCell];
            [cell setError: error_];
            [self addTableViewCell: cell inSection: eASDTSvOpTableViewSection_Output];
            [dCell_Error setObject: cell forKey: reason];
        }        
    }
}
- (void)            updateErrors {
    do {
        if ( asd_Request == nil ) {
            break;
        }
        [self addError: [asd_Request connectionError]];
        ASDPrBase *parser = [asd_Request parser];
        if ( [parser matchErrors] != nil ) {
            for ( NSError *error in [parser matchErrors] ) {
                [self addError: error];
            }
        }
    } while ( false );
}
- (void)            updateHttpStatus {
    if ( asd_Request != nil ) {
        if ( tcl_HttpStatus == nil ) {
            tcl_HttpStatus = [[TASDTcHttpStatus tableCell] retain];
        }
        if ( asd_Request.httpResponse != nil ) {
            NSInteger statusCode = [[asd_Request httpResponse] statusCode];
            [tcl_HttpStatus setStatusCode: statusCode];
        } else {
            [tcl_HttpStatus setStatusCode: 0];
        }
        if ( asd_Request.startTime != nil && asd_Request.endTime != nil ) {
            NSTimeInterval duration = [[asd_Request endTime] timeIntervalSinceDate: [asd_Request startTime]];
            [tcl_HttpStatus setDuration: duration];
        } else {
            [tcl_HttpStatus setDuration: 0];
        }
        [self addTableViewCell: tcl_HttpStatus inSection: eASDTSvOpTableViewSection_Output];
    }
}
- (void)            updateUiState {
    BOOL          canReview = FALSE;
    BOOL          canLaunch = ( asd_Request == nil );
    ASDSpResult  *result    = ( asd_Request == nil ? nil : [[asd_Request result] retain] );
    if ( result != nil ) {
        canReview = [result isDone];
    } else {
        lbl_Status.text = [NSString string];
    }
    if ( [aiv_Activity isAnimating] ) {
        if ( canLaunch || canReview ) {
            [aiv_Activity stopAnimating];
        }
    } else {
        if ( !canLaunch && !canReview ) {
            [aiv_Activity startAnimating];
        }
    }
    if ( canReview ) {
        self.navigationItem.rightBarButtonItem = bbn_Reset;
    } else {
        self.navigationItem.rightBarButtonItem = bbn_Queue;
        bbn_Queue.enabled = canLaunch;
    }
    
    [result release];
}
- (void)            updateUrlRequest {
    do {
        if ( asd_Request == nil ) {
            break;
        }
        NSURLRequest *urlRequest = [[asd_Request urlRequest] retain];
        if ( urlRequest == nil ) {
            break;
        }
        if ( tcl_UrlRequest == nil ) {
            tcl_UrlRequest = [[TASDTcUrlRequest tableCell] retain];
        }
        [tcl_UrlRequest setUrlRequest: asd_Request.urlRequest];
        [self addTableViewCell: tcl_UrlRequest inSection: eASDTSvOpTableViewSection_Run];
        [urlRequest release];
    } while ( false );
}
- (void)            notificationHandlerOp: (ASDSpNotification*) notify_ {
    NSString *msg = [[notify_ description] retain];
    [[self lblStatus] setText: msg];
    [msg release];
    [self updateUiState];
    [self updateHttpStatus];
    [self updateUrlRequest];
    [self updateAwsResponse];
    [self updateErrors];
}
- (void)            notificationHandlerConfig: (ASDSpNotification*) notify_ {
    [self updateAwsInfo];
    [[self tableView] reloadData];
}
- (void)            notificationAddSelf {
    [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(notificationHandlerConfig:) name: [TASDConfigManager kNotification] object: nil];
}
- (void)            notificationRemoveSelf {
    [[NSNotificationCenter defaultCenter] removeObserver: self];
}
#pragma mark -- UIButton event handlers
- (IBAction)        btnResetPress {
    mASDreleaseNil( asd_Request );
    [self updateUiState];
    [self removeTableViewCell: tcl_Run         inSection: eASDTSvOpTableViewSection_Run];
    [self removeTableViewCell: tcl_UrlRequest  inSection: eASDTSvOpTableViewSection_Run];
    [self removeTableViewCell: tcl_HttpStatus  inSection: eASDTSvOpTableViewSection_Output];
    [self removeTableViewCell: tcl_AwsResponse inSection: eASDTSvOpTableViewSection_Output];
    if ( dCell_Error != nil && 0 < [dCell_Error count] ) {
        NSArray *aCell_Error = [[dCell_Error allValues] retain];
        for ( UITableViewCell *cell in aCell_Error ) {
            [self removeTableViewCell: cell inSection: eASDTSvOpTableViewSection_Output];
        }
        [aCell_Error release];
        [dCell_Error removeAllObjects];
    }
    [[super tableView] reloadData];
}
- (IBAction)        btnQueuePress {
    UIAlertView *alert = [[UIAlertView alloc] initWithTitle: NSStringFromSelector( _cmd ) 
                                                    message: @"Not implemented - override in derived class" 
                                                   delegate: self cancelButtonTitle: @"Ok" otherButtonTitles: nil];
    [alert show];
    [alert release];
}
#pragma mark -- UITableViewDelegate
- (UITableViewCell*)    cellForRowAtIndexPath: (NSIndexPath*) indexPath_ {
    return (  indexPath_.section == eASDTSvOpTableViewSection_Input  ? [aCell_Input  objectAtIndex: indexPath_.row ]
            : indexPath_.section == eASDTSvOpTableViewSection_Run    ? [aCell_Run    objectAtIndex: indexPath_.row ]
            : indexPath_.section == eASDTSvOpTableViewSection_Output ? [aCell_Output objectAtIndex: indexPath_.row] : nil );
}
#pragma mark -- UITableViewDataSource
- (NSInteger)           numberOfSectionsInTableView: (UITableView*) tableView_ {
    return eASDTSvOpTableViewSection_count;
}
- (UITableViewCell*)    tableView: (UITableView*) tableView_ cellForRowAtIndexPath: (NSIndexPath*) indexPath_ {
    return [self cellForRowAtIndexPath: indexPath_];
}
- (NSInteger)           tableView: (UITableView*) tableView_ numberOfRowsInSection: (NSInteger) section_ {
    return (  section_ == eASDTSvOpTableViewSection_Input  ? [aCell_Input  count]
            : section_ == eASDTSvOpTableViewSection_Run    ? [aCell_Run    count]
            : section_ == eASDTSvOpTableViewSection_Output ? [aCell_Output count] : 0 );
}
- (NSString*)           tableView: (UITableView*) tableView_ titleForHeaderInSection: (NSInteger) section_ {
    return (  section_ == eASDTSvOpTableViewSection_Output ? (0 < [aCell_Output count] ? @"Outputs" : nil )
            : section_ == eASDTSvOpTableViewSection_Run    ? nil
            : section_ == eASDTSvOpTableViewSection_Input  ? @"Inputs" : @"Invalid" );
}
#pragma mark -- UITableViewDelegate
- (void)                tableView: (UITableView*) tableView_ accessoryButtonTappedForRowWithIndexPath: (NSIndexPath*) indexPath_ {
    UITableViewCell *cell = [[self tableView: tableView_ cellForRowAtIndexPath: indexPath_] retain];
    if ( [cell isKindOfClass: [TASDTcBase class]] ) {
        TASDTcBase        *baseCell     = (TASDTcBase*) cell;
        NSDictionary      *dictDisplay  = [[baseCell dictDisplayFromRequest: asd_Request] retain];
        TASDSvDictionary  *svDictionary = [[TASDSvDictionary alloc] initWithDictionary: dictDisplay];
        [svDictionary setTitle: [baseCell title]];
        [[self navigationController] pushViewController: svDictionary animated: YES];
        [dictDisplay  release];
        [svDictionary release];
    }
    [cell release];
}

#pragma mark -- public methods ( for use by derived classes )
- (void)        addTableViewCell: (UITableViewCell*) cell inSection: (NSUInteger) sectionId_ {
    if ( sectionId_ == eASDTSvOpTableViewSection_Input ) {
        if ( ![aCell_Input containsObject: cell] ) {
            [aCell_Input addObject: cell];            
            [[super tableView] reloadData];
        }
    }
    if ( sectionId_ == eASDTSvOpTableViewSection_Run ) {
        if ( ![aCell_Run containsObject: cell] ) {
            [aCell_Run addObject: cell];            
            [[super tableView] reloadData];
        }
    }
    if ( sectionId_ == eASDTSvOpTableViewSection_Output ) {
        if ( ![aCell_Output containsObject: cell] ) {
            [aCell_Output addObject: cell];            
            [[super tableView] reloadData];
        }
    }
}
- (void)        removeTableViewCell: (UITableViewCell*) cell inSection: (NSUInteger) sectionId_ {
    if ( sectionId_ == eASDTSvOpTableViewSection_Input ) {
        if ( [aCell_Input containsObject: cell ] ) {
            [aCell_Input removeObject: cell];
            [[super tableView] reloadData];            
        }
    }
    if ( sectionId_ == eASDTSvOpTableViewSection_Run ) {
        if ( [aCell_Run containsObject: cell ] ) {
            [aCell_Run removeObject: cell];
            [[super tableView] reloadData];            
        }
    }
    if ( sectionId_ == eASDTSvOpTableViewSection_Output ) {
        if ( [aCell_Output containsObject: cell ] ) {
            [aCell_Output removeObject: cell];
            [[super tableView] reloadData];            
        }
    }
}
- (void)        queueRequest: (ASDRqBase*) asdRequest_ {
    do {
        if ( asd_Request != nil ) {
            NSLog(@"Ignoring new request# %u %@ - have active request already",
                  asdRequest_.sequenceNumber,[[asdRequest_ class] kOperationName]);
            break;
        }
        [self addTableViewCell: tcl_Run        inSection: eASDTSvOpTableViewSection_Run];
        
        asd_Request = [asdRequest_ retain];
        [[NSNotificationCenter defaultCenter] addObserver: self selector: @selector(notificationHandlerOp:) name: [[asd_Request class] kNotificationName] object: nil];
        AppDelegate_Shared  *appShared  = [[UIApplication sharedApplication] delegate];
        [[appShared operationQueue] addOperation: asd_Request];
        
        [self updateUiState];
    } while ( false );
}

#pragma mark -- UIView standard
@synthesize tclAwsInfo       = tcl_AwsInfo;
@synthesize tclRun           = tcl_Run;

@synthesize aivActivity      = aiv_Activity;
@synthesize lblAccountName   = lbl_AccountName;
@synthesize lblEndpointName  = lbl_EndpointName;
@synthesize lblStatus        = lbl_Status;

@synthesize cfgEndpoint      = cfg_Endpoint;
@synthesize cfgSigProvider   = cfg_SigProvider;
@synthesize asdRequest       = asd_Request;

- (void)            viewDidLoad {
    [super viewDidLoad];

    [self updateAwsInfo];
    [self notificationAddSelf];
    
    aCell_Input   = [[NSMutableArray alloc] initWithCapacity: 8];
    aCell_Run     = [[NSMutableArray alloc] initWithCapacity: 8];
    aCell_Output  = [[NSMutableArray alloc] initWithCapacity: 8];
    
    bbn_Reset     = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemTrash target: self action: @selector(btnResetPress)];
    bbn_Queue     = [[UIBarButtonItem alloc] initWithBarButtonSystemItem: UIBarButtonSystemItemAction target: self action: @selector(btnQueuePress)];
    
    [[self navigationItem] setTitle: [self title]];
    
    [self addTableViewCell: tcl_AwsInfo inSection: eASDTSvOpTableViewSection_Input ];
    [self updateUiState];
}
- (BOOL)            shouldAutorotateToInterfaceOrientation:(UIInterfaceOrientation)interfaceOrientation {
    return YES;
}
- (void)            didReceiveMemoryWarning {
    [super didReceiveMemoryWarning];
    mASDreleaseNil( asd_Request );
    [self updateUiState];
}
- (void)            viewDidUnload {
    [super viewDidUnload];
    [self notificationRemoveSelf];
    
    mASDreleaseNil( aCell_Input  );
    mASDreleaseNil( aCell_Run    );
    mASDreleaseNil( aCell_Output );
    mASDreleaseNil( dCell_Error  );
    
    self.aivActivity        = nil;
    self.lblAccountName     = nil;
    self.lblEndpointName    = nil;
    self.lblStatus          = nil;
    
    self.tclAwsInfo         = nil;
    self.tclRun             = nil;
    
    self.navigationItem.rightBarButtonItem = nil;
    
    mASDreleaseNil( bbn_Reset       );
    mASDreleaseNil( bbn_Queue       );
    
    mASDreleaseNil( tcl_HttpStatus  );
    mASDreleaseNil( tcl_UrlRequest  );
    
    mASDreleaseNil( cfg_SigProvider );
    mASDreleaseNil( cfg_Endpoint    );
}
- (void)            dealloc {
    [cfg_SigProvider    release];
    [cfg_Endpoint       release];
    [super dealloc];
}
@end
